package top.superflow.flow.manage

import javax.annotation.PostConstruct
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.ApplicationContext
import org.springframework.stereotype.Component
import top.superflow.context.imp.{DBContext, PlatformContext}
import top.superflow.context.manage.SuperFlowContextManager
import top.superflow.core.pool.resource.imp.GlobalResourcePoolManager
import top.superflow.engine.runtime.{DefaultEngineConfig, DefaultRuntimeFlowEngine}
import top.superflow.exception.Exceptable
import top.superflow.flow.config.parse.ParserManager
import top.superflow.flow.config.parse.center.GlobalParserCenter
import top.superflow.flow.load.LoadManager
import top.superflow.flow.runtime.cache.FlowRunTimeCache
import top.superflow.flow.runtime.flow.ExtFlow
import top.superflow.flow.runtime.inf.defaults.DefaultGeneralRequest
import top.superflow.flow.runtime.inf.{GeneralRequest, GeneralResponse}
import top.superflow.flow.validate.ValidateManager
import top.superflow.lang.StringUtils
import top.superflow.log.Loggable

import scala.collection.mutable
import scala.concurrent.duration._
import scala.concurrent.{Await, AwaitPermission, CanAwait, Future}

@Component
class FlowManager extends Loggable with Exceptable{

  @Autowired
  private val loadManager: LoadManager = null

  @Autowired
  private val validateManager: ValidateManager = null

  @Autowired
  private val globalResourcePoolManager : GlobalResourcePoolManager = null

  @Autowired
  private val parserManager: ParserManager = null


  @Autowired
  private val applicationContext : ApplicationContext = null


  @Autowired
  private val superFlowContextManager : SuperFlowContextManager = null


  @Autowired
  private val runtimeFlowEngine : DefaultRuntimeFlowEngine = null

  @Autowired
  private val platformContext : PlatformContext = null



//  @Autowired
//  var resourcePoolManager: DefaultResourcePoolManager = _

  @PostConstruct
  private def init{
    platformContext.init
    GlobalParserCenter.getInstance.init(getDependencies)
    val flowConfiguration = loadManager.load
    validateManager.isValid(flowConfiguration)
    parserManager.parse(flowConfiguration)
    runtimeFlowEngine.initialize(new DefaultEngineConfig)
  }

  def execute(group: String, flowKey : String, anyRequest : Any*) : Any = {
    if(StringUtils.isBlank(flowKey)){
      throwRequestUnsupportedException("The flow key should not be null!")
    }

    val flow = FlowRunTimeCache.getInstance.get(group, flowKey, classOf[ExtFlow])
    if(flow == null){
      throwRequestUnsupportedException("There is no corresponding flow for group {} flow key {}", group, flowKey)
    }
    val futureResult = runtimeFlowEngine.execute(flow.asInstanceOf[ExtFlow], toGeneralRequest(anyRequest))

    val response = Await.result(futureResult, Duration.Inf)

    response
  }


  private def getDependencies : Map[String, Any] = {
    val dependencies = mutable.Map.empty[String, Any]
    dependencies.put("applicationContext", applicationContext)

    dependencies.toMap
  }

  def execute(groupId : String, key : String, args : Map[String, _]): Future[GeneralResponse] ={
    executeWithGeneralRequest(groupId, key, ()=>{toGeneralRequest(args)})
  }

  def execute(groupId : String, key : String, requestBody : Any): Future[GeneralResponse] ={
    executeWithGeneralRequest(groupId, key, ()=>{toGeneralRequest(requestBody)})
  }



  private def executeWithGeneralRequest(groupId: String, key: String, toGeneralRequestFun : Function0[GeneralRequest]) = {
    val expectedFlow = FlowRunTimeCache.getInstance.get(groupId, key, classOf[ExtFlow])

    if (expectedFlow == null) {
      throwRequestUnsupportedException("There is no corresponding flow for the group {}, key {}", groupId, key)
    }

    val generalRequest = toGeneralRequestFun.apply()

    runtimeFlowEngine.execute(expectedFlow.asInstanceOf[ExtFlow], generalRequest)
  }

  private def toGeneralRequest(args : Map[String, _]): GeneralRequest ={
    val defaultGeneralRequest = new DefaultGeneralRequest
    defaultGeneralRequest.addParameters(args)

    defaultGeneralRequest
  }

  private def toGeneralRequest(requestBody : Any): GeneralRequest ={
    val defaultGeneralRequest = new DefaultGeneralRequest
    defaultGeneralRequest.setRequestBody(requestBody)

    defaultGeneralRequest
  }

}

object FlowManager {


}